package zhongbo.java.air.flightpath.service.impl;

import cn.hutool.core.text.CharSequenceUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import zhongbo.java.air.common.exception.BusinessException;
import zhongbo.java.air.common.exception.ExceptionCode;
import zhongbo.java.air.common.exception.NoStackLogException;
import zhongbo.java.air.common.util.NumberUtil;
import zhongbo.java.air.common.vo.PageVo;
import zhongbo.java.air.flightpath.listener.RedisLogChanelPublisher;
import zhongbo.java.air.flightpath.mapper.FlightPathMapper;
import zhongbo.java.air.flightpath.model.entities.FlightPath;
import zhongbo.java.air.common.enums.OperationEnum;
import zhongbo.java.air.flightpath.model.vo.LogVo;
import zhongbo.java.air.flightpath.service.IFlightPathService;


import java.util.Date;
import java.util.Objects;

/**
 * @author WeiJin
 * @version 1.0
 * @date 2025/3/31 11:26
 */
@Service
public class FlightPathServiceImpl implements IFlightPathService {

    @Autowired
    private FlightPathMapper flightPathMapper;
    @Autowired
    private RedisLogChanelPublisher redisLogChanelPublisher;

    @Override
    public FlightPath saveFlightPath(FlightPath flightPath) {
        // 参数校验
        validFlightPath(flightPath);

        // 新增时给当前时间时间戳
        flightPath.setTimestamp(new Date());
        int inserted = flightPathMapper.insert(flightPath);
        // 根据影响表中记录数做出相应的返回
        if (inserted > 0) {
            // 新增成功 redis发布日志消息
            LogVo logVo = LogVo.builder().time(new Date())
                    .message("新增飞行轨迹")
                    .type(OperationEnum.INSERT)
                    .info(flightPath)
                    .build();
            redisLogChanelPublisher.publish(logVo);
            return flightPath;
        }
        throw new BusinessException(ExceptionCode.SAVE_FAILED);
    }

    @Override
    public String delFlightPath(String id) {
        int deleted = flightPathMapper.deleteById(id);
        // 影响数据库记录条数做出相应的返回
        if (deleted > 0) {
            // 删除成功发布日志
            LogVo logVo = LogVo.builder().time(new Date())
                    .message("删除飞行轨迹")
                    .type(OperationEnum.DELETE)
                    .info(id)
                    .build();
            redisLogChanelPublisher.publish(logVo);
            return id;
        }
        throw new BusinessException(ExceptionCode.DELETE_FAILED);
    }

    @Override
    public FlightPath modifyFlightPath(FlightPath flightPath) {
        // 参数校验
        validFlightPath(flightPath);
        // 单独校验id
        if (CharSequenceUtil.isBlank(flightPath.getId())) {
            throw new BusinessException(ExceptionCode.ID_NOT_NULL);
        }
        // 修改时先查询要修改的飞机id是否存在
        FlightPath unModifyFlightPath = queryById(flightPath.getId());
        if (Objects.isNull(unModifyFlightPath)) {
            throw new BusinessException(ExceptionCode.ALERT_ZONE_NOT_EXIST);
        }

        int updated = flightPathMapper.updateById(flightPath);

        // 修改成功，查询出修改后的信息，返回
        if (updated > 0) {
            // 查询修改后的飞行轨迹信息
            FlightPath modifiedFlight = queryById(flightPath.getId());
            // 修改成功 redis发布日志消息
            LogVo logVo = LogVo.builder().time(new Date())
                    .message("修改飞行轨迹")
                    .type(OperationEnum.UPDATE)
                    .info(flightPath)
                    .build();
            redisLogChanelPublisher.publish(logVo);
            return modifiedFlight;
        }
        // 修改失败 抛出异常
        throw new BusinessException(ExceptionCode.UPDATE_FAILED);
    }

    @Override
    public FlightPath queryById(String id) {
        FlightPath flightPath = flightPathMapper.selectById(id);
        // 查询不到，抛出不存在异常
        if (Objects.isNull(flightPath)) {
            throw new BusinessException(ExceptionCode.CURRENT_ID_NOT_EXIST);
        }
        // 查询后redis发布信息
        LogVo logVo = LogVo.builder().time(new Date())
                .message("根据飞行轨迹id查询飞行轨迹")
                .type(OperationEnum.SELECT)
                .info(flightPath)
                .build();
        redisLogChanelPublisher.publish(logVo);
        return flightPath;
    }

    @Override
    public PageVo<FlightPath> pageFlightPath(Integer pageNumber, Integer pageSize, String sourceType,
                                             String orderBy, Boolean orderType) {
        QueryWrapper<FlightPath> wrapper = new QueryWrapper<>();
        IPage<FlightPath> page = new Page<>(pageNumber, pageSize);
        // 数据源类型不为空，添加查询条件
        wrapper.eq(CharSequenceUtil.isNotBlank(sourceType), "source_type", sourceType);
        // 排序字段不为空，添加相应的排序
        if (CharSequenceUtil.isNotBlank(orderBy)) {
            // 升序
            if (Boolean.TRUE.equals(orderType)) {
                wrapper.orderByAsc(orderBy);
            } else {
                // 降序
                wrapper.orderByDesc(orderBy);
            }
        }
        // 查询
        IPage<FlightPath> flightPathPage = flightPathMapper.selectPage(page, wrapper);
        PageVo<FlightPath> pageVo = new PageVo<>(flightPathPage);
        LogVo logVo = LogVo.builder().time(new Date())
                .message("分页获取飞行轨迹")
                .type(OperationEnum.SELECT)
                .info(pageVo)
                .build();
        // 分页查询后redis发布信息
        redisLogChanelPublisher.publish(logVo);
        return pageVo;
    }


    private void validFlightPath(FlightPath flightPath) {
        // 非空校验
        if (Objects.isNull(flightPath)) {
            throw new NoStackLogException("请求参数不能为空");
        }
        if (CharSequenceUtil.isBlank(flightPath.getIcaoCode())) {
            throw new NoStackLogException("icaoCode 不能为空");
        }
        if (Objects.isNull(flightPath.getLatitude())) {
            throw new NoStackLogException("latitude 不能为空");
        }
        if (Objects.isNull(flightPath.getLongitude())) {
            throw new NoStackLogException("longitude 不能为空");
        }
        if (Objects.isNull(flightPath.getAltitude())) {
            throw new NoStackLogException("altitude 不能为空");
        }
        if (Objects.isNull(flightPath.getSourceType())) {
            throw new NoStackLogException("sourceType 不能为空");
        }
        // 长度校验
        if (flightPath.getIcaoCode().length() > 6) {
            throw new NoStackLogException("参数icaoCode长度最长为6");
        }
        // 经纬度小数校验
        if (NumberUtil.validDecimal(flightPath.getLatitude(), 3, 6)) {
            throw new NoStackLogException("参数latitude整数部分最多3位，小数部分多6位");
        }
        if (NumberUtil.validDecimal(flightPath.getLongitude(), 3, 6)) {
            throw new NoStackLogException("参数longitude整数部分最多3位，小数部分多6位");
        }
        if (!NumberUtil.validInteger(flightPath.getAltitude(), 11)) {
            throw new NoStackLogException("参数altitude最多11位");
        }

        // 地速、航向角不为空数值校验
        if (Objects.nonNull(flightPath.getSpeed()) && !NumberUtil.validInteger(flightPath.getSpeed(), 6)) {
            throw new NoStackLogException("参数speed长度最长为6位");
        }
        if (Objects.nonNull(flightPath.getHeading()) && (flightPath.getHeading() < 0 || flightPath.getHeading() > 359)) {
            throw new NoStackLogException("参数heading范围只能是0-359");
        }
    }
}
